/*
Copyright 2010 Iain Surgey.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  

See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/

vec3	RTF_v, RTF_v2;

#__body__

/*
===============
R_SetupFrame
===============
*/
private function R_SetupFrame ()
{
	#{d| int			i}
	
	r_framecount++;
	r_zframe++;
	if (r_zframe >= 0xFFFF) {
		for (i in 0...RESH*RESV) {
			Memory.setI32(#{zbuffer}+(i<<2),0);
		}
		r_zframe = 1;
	}
	
	r_zmmframe+=0x400000;
	if (r_zmmframe >= 0x7FC00000) {
		for (i in 0...RESH) {
			Memory.setI32(#{zminmaxs}+(i<<2),0);
		}
		r_zmmframe = 0x400000;
	}
	
// build the transformation matrix for the given view angles
	VectorCopy (#{vieworg}, #{r_origin});
	AngleVectors (#{viewangles}, #{vpn.p}, #{vright.p}, #{vup.p});
	
	r_viewleaf = Mod_PointInLeaf ();
	r_viewcluster = #{r_viewleaf->cluster};
	
// start off with just the four screen edge clip planes
	R_TransformFrustum ();
	R_SetUpFrustumIndexes ();
	
// save base values
	VectorCopy (#{vpn.p}, #{base_vpn.p});
	VectorCopy (#{vright.p}, #{base_vright.p});
	VectorCopy (#{vup.p}, #{base_vup.p});
	
// clear frame counts
	c_faceclip = 0;
	r_polycount = 0;
	r_drawnpolycount = 0;
	r_amodels_drawn = 0;
	r_outofsurfaces = 0;
	r_outofedges = 0;
	d_minmip = 0;
	
	alias_visible = false;
}



/*
===============
R_ViewChanged

Called every time the vid structure or r_refdef changes.
Guaranteed to be called before the first refresh
* FIX THIS - SHOULD ONLY BE CALLED ON FIRST FRAME
===============
*/
private function R_ViewChanged ()
{
	#{d| int		i}
	#{d| float scale_for_mip}
	
	horizontalFieldOfView = 2*Math.tan(fov_x/360*3.14159265358979323846);
	verticalFieldOfView = 2*Math.tan(fov_y/360*3.14159265358979323846);
	
	ord_fvrectx = scr_x;
	ord_fvrectx_adj = scr_x - 0.5;
	ord_vrect_x_adj_shift20 = (scr_x<<20) + (1<<19) - 1;
	ord_fvrecty = scr_y;
	ord_fvrecty_adj = scr_y - 0.5;
	ord_vrectright = scr_x + scr_width;
	ord_vrectright_adj_shift20 = (ord_vrectright<<20) + (1<<19) - 1;
	ord_fvrectright = ord_vrectright;
	ord_fvrectright_adj = ord_vrectright - 0.5;
	ord_vrectrightedge = ord_vrectright - 0.99;
	ord_vrectbottom = scr_y + scr_height;
	ord_fvrectbottom = ord_vrectbottom;
	ord_fvrectbottom_adj = ord_vrectbottom - 0.5;
	
	ord_aliasvrect_x = Std.int(scr_x * r_aliasuvscale);
	ord_aliasvrect_y = Std.int(scr_y * r_aliasuvscale);
	ord_aliasvrect_width = Std.int(scr_width * r_aliasuvscale);
	ord_aliasvrect_height = Std.int(scr_height * r_aliasuvscale);
	ord_aliasvrectright = ord_aliasvrect_x +
			ord_aliasvrect_width;
	ord_aliasvrectbottom = ord_aliasvrect_y +
			ord_aliasvrect_height;
	
// values for perspective projection
// if math were exact, the values would range from 0.5 to to range+0.5
// hopefully they wll be in the 0.000001 to range+.999999 and truncate
// the polygon rasterization will never render in the first row or column
// but will definately render in the [range] row and column, so adjust the
// buffer origin to get an exact edge to edge fill
	xcenter = (scr_width * XCENTERING) + scr_x - 0.5;
	aliasxcenter = xcenter * r_aliasuvscale;
	ycenter = (scr_height * YCENTERING) + scr_y - 0.5;
	aliasycenter = ycenter * r_aliasuvscale;

	xscale = scr_width / horizontalFieldOfView;
	aliasxscale = xscale * r_aliasuvscale;
	xscaleinv = 1.0 / xscale;
	
	yscale = xscale;
	aliasyscale = yscale * r_aliasuvscale;
	yscaleinv = 1.0 / yscale;
	xscaleshrink = (scr_width-6)/horizontalFieldOfView;
	yscaleshrink = xscaleshrink;

// left side clip
	#{screenedge[0].normal.p[0] = -1.0 / (xOrigin*horizontalFieldOfView)};
	#{screenedge[0].normal.p[1] = 0};
	#{screenedge[0].normal.p[2] = 1};
	#{screenedge[0].type = PLANE_ANYZ};
	
// right side clip
	#{screenedge[1].normal.p[0] = 1.0 / ((1.0-xOrigin)*horizontalFieldOfView)};
	#{screenedge[1].normal.p[1] = 0};
	#{screenedge[1].normal.p[2] = 1};
	#{screenedge[1].type = PLANE_ANYZ};
	
// top side clip
	#{screenedge[2].normal.p[0] = 0};
	#{screenedge[2].normal.p[1] = -1.0 / (yOrigin*verticalFieldOfView)};
	#{screenedge[2].normal.p[2] = 1};
	#{screenedge[2].type = PLANE_ANYZ};
	
// bottom side clip
	#{screenedge[3].normal.p[0] = 0};
	#{screenedge[3].normal.p[1] = 1.0 / ((1.0-yOrigin)*verticalFieldOfView)};
	#{screenedge[3].normal.p[2] = 1};	
	#{screenedge[3].type = PLANE_ANYZ};
	
	for (i in 0...4)
		VectorNormalize (#{screenedge[i].normal.p});
	
	scale_for_mip = xscale;
	if (yscale > xscale)
		scale_for_mip = yscale;
	
	d_scalemip0 = ((1.0*4.0)/scale_for_mip);
	d_scalemip1 = ((0.5*0.8*4.0)/scale_for_mip);
	d_scalemip2 = ((0.25*0.8*4.0)/scale_for_mip);
	
}


/*
===================
R_TransformFrustum
===================
*/
private function R_TransformFrustum ()
{
	#{d| int		i}
	
	for (i in 0...4)
	{
		
		#{RTF_v.p[0] = screenedge[i].normal.p[2]};
		#{RTF_v.p[1] = -screenedge[i].normal.p[0]};
		#{RTF_v.p[2] = screenedge[i].normal.p[1]};

		#{RTF_v2.p[0] = RTF_v.p[1]*vright.p[0] + RTF_v.p[2]*vup.p[0] + RTF_v.p[0]*vpn.p[0]};
		#{RTF_v2.p[1] = RTF_v.p[1]*vright.p[1] + RTF_v.p[2]*vup.p[1] + RTF_v.p[0]*vpn.p[1]};
		#{RTF_v2.p[2] = RTF_v.p[1]*vright.p[2] + RTF_v.p[2]*vup.p[2] + RTF_v.p[0]*vpn.p[2]};
		
		VectorCopy (#{RTF_v2.p}, #{view_clipplanes[i].normal.p});

		#{view_clipplanes[i].dist = #[DotProduct (]#r_origin#[, ]#RTF_v2.p)};
	}
}

/*
===============
R_SetUpFrustumIndexes
===============
*/
private function R_SetUpFrustumIndexes ()
{
	#{d| int		i, j, *pindex}

	#{pindex = r_frustum_indexes};

	for (i in 0...4)
	{
		for (j in 0...3)
		{
			if (#{view_clipplanes[i].normal.p[j]} < 0)
			{
				#{pindex[j] = j};
				#{pindex[j+3] = j+3};
			}
			else
			{
				#{pindex[j] = j+3};
				#{pindex[j+3] = j};
			}
		}

	// FIXME: do just once at start
		#{pfrustum_indexes[i] = pindex};
		pindex += 6*4;
	}
}

/*
================
TransformVector
================
*/
private inline function TransformVector (vin : Int, out : Int)
{
	Memory.setFloat(out,DotProduct(vin,#{vright.p}));
	Memory.setFloat(out+4,DotProduct(vin,#{vup.p}));
	Memory.setFloat(out+8,DotProduct(vin,#{vpn.p}));		
}

